package org.zjvis.datascience.common.graph.exporter;

import com.alibaba.fastjson.JSONObject;
import org.zjvis.datascience.common.graph.util.GraphUtil;
import org.zjvis.datascience.common.vo.graph.LinkVO;
import org.zjvis.datascience.common.vo.graph.NodeVO;

import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;

/**
 * @description ExporterGML
 * @date 2021-12-29
 */
public class ExporterGML extends Exporter {
    private Writer writer;
    private int spaces = 2;
    private int currentSpaces = 0;

    public ExporterGML() {

    }

    public boolean execute() {
        boolean ret = true;
        try {
            exportData();
        } catch (IOException e) {
            logger.warn("" + e.getMessage());
            ret = false;
        }
        return ret;
    }



    private void printOpen(String s) throws IOException {
        int i;
        for(i = 0; i < this.currentSpaces; ++i) {
            this.writer.write(32);
        }

        this.writer.write(s + "\n");

        for(i = 0; i < this.currentSpaces; ++i) {
            this.writer.write(32);
        }

        this.writer.write("[\n");
        this.currentSpaces += this.spaces;
    }

    private void printClose() throws IOException {
        this.currentSpaces -= this.spaces;

        for(int i = 0; i < this.currentSpaces; ++i) {
            this.writer.write(32);
        }

        this.writer.write("]\n");
    }

    private void printTag(String s) throws IOException {
        for(int i = 0; i < this.currentSpaces; ++i) {
            this.writer.write(32);
        }

        this.writer.write(s + "\n");
    }

    private void printJSONObject(String tag, JSONObject jsonObject) throws IOException {
        printOpen(tag);
        for (String key: jsonObject.keySet()) {
            Object value = jsonObject.get(key);
            if (value == null) {
                continue;
            }
            if (value instanceof JSONObject) {
                printJSONObject(key, (JSONObject) value);
            } else {
                if (value instanceof String) {
                    printTag(key + " " + fieldContentFormat((String) value));
                } else {
                    printTag(key + " " + value);
                }
            }
        }
        printClose();
    }

    private void exportData() throws IOException{
        printOpen("graph");
        Iterator<NodeVO> nodeIter = nodes.iterator();
        while (nodeIter.hasNext()) {
            NodeVO node = nodeIter.next();
            printNode(node);
        }

        Iterator<LinkVO> linkIter = links.iterator();
        while (linkIter.hasNext()) {
            LinkVO link = linkIter.next();
            printLink(link);
        }

        printClose();
    }

    private void printNode(NodeVO node) throws IOException {
        printOpen("node");
        printTag("id " + node.getOrderId());
        String categoryId = labelMap == null ? GraphUtil.removeAliasId(node.getCategoryId(), graphId) : labelMap.get(node.getCategoryId());
        printTag("categoryId " + fieldContentFormat(categoryId));
        printTag("label " + fieldContentFormat(node.getLabel()));

        JSONObject attributes = new JSONObject();
        makeAttributes(node.getAttrs(), attributes, node.getId(), node.getCategoryId(), multiValueHelper, metricResults);
        printJSONObject("attributes", attributes);

        JSONObject config = new JSONObject();
        makeNodeCfg(config, node);
        printJSONObject("config", config);

        printClose();
    }

    private void printLink(LinkVO link) throws IOException {
        printOpen("link");
        printTag("id " + link.getOrderId());
        printTag("source " + Long.parseLong(GraphUtil.removeAliasId(link.getSource(), graphId)));
        printTag("target " + Long.parseLong(GraphUtil.removeAliasId(link.getTarget(), graphId)));
        printTag("label " + fieldContentFormat(link.getLabel()));
        printTag("directed " + link.getDirected());
        printTag("weight " + link.getWeight());

        JSONObject attributes = new JSONObject();
        makeAttributes(link.getAttrs(), attributes, link.getId(), link.getEdgeId(), multiValueHelper, null);
        printJSONObject("attributes", attributes);

        JSONObject config = new JSONObject();
        makeLinkCfg(config, link);
        printJSONObject("config", config);

        printClose();
    }


    public void setWriter(Writer writer) {
        this.writer = writer;
    }
}
